﻿// <copyright file="GeometryModel3D.cs" company="Axelerate Solutions S.A.">
// Copyright (c) Axelerate Solutions S.A.  All rights reserved.
// </copyright>

namespace Axelerate.Silverlight3D.Media.Media3D
{
    using System;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Ink;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using System.Collections.Generic;

    /// <summary>
    /// File name: GeometryModel3D.cs
    /// Company: Axelerate Solutions S.A.
    /// Created By: Daniel Rojas
    /// Created Date: 10/16/2008 11:11:00 h.
    /// Description: Creates a 3-D model comprised of a MeshGeometry3D and a Material.
    ///   <Modifications>
    ///   </Modifications>
    /// </summary>
    public sealed class GeometryModel3D : Model3D
    {
        #region Fields
        /// <summary>
        /// Identifies the BackMaterial dependency property.
        /// </summary>
        public static readonly DependencyProperty BackMaterialProperty =
                    DependencyProperty.Register(
                          "BackMaterial",
                          typeof(Material),
                          typeof(GeometryModel3D),
                          new PropertyMetadata(OnBackMaterialPropertyChanged));

        /// <summary>
        /// Identifies the Geometry dependency property.
        /// </summary>
        public static readonly DependencyProperty GeometryProperty =
                    DependencyProperty.Register(
                          "Geometry",
                          typeof(Geometry3D),
                          typeof(GeometryModel3D),
                          new PropertyMetadata(OnGeometryPropertyChanged));

        /// <summary>
        /// Identifies the Material dependency property.
        /// </summary>
        public static readonly DependencyProperty MaterialProperty =
                    DependencyProperty.Register(
                          "Material",
                          typeof(Material),
                          typeof(GeometryModel3D),
                          new PropertyMetadata(OnMaterialPropertyChanged));
        #endregion

        #region Properties
        /// <summary>
        /// Gets or sets the Material to be applied to the back of a Model3D. This is a dependency property.
        /// </summary>
        public Material BackMaterial
        {
            get
            {

                return (Material)this.GetValue(BackMaterialProperty);
            }
            set
            {
                Material OldValue = (Material)this.GetValue(BackMaterialProperty);
                if (OldValue != null)
                {
                    OldValue.PropertyChanged -= this.BackMaterialPropertyValue_PropertyChanged;
                }
                this.SetValue(BackMaterialProperty, value);
                value.PropertyChanged += this.BackMaterialPropertyValue_PropertyChanged;
            }
        }

        /// <summary>
        /// Notify if the some property of the BackMaterial was changed
        /// </summary>
        /// <param name="sender">Object that send the event</param>
        /// <param name="e">event arguments</param>
        void BackMaterialPropertyValue_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            this.IsDirty = true;
            this.NotifyPropertyChanged("BackMaterial");
        }

        /// <summary>
        /// Gets or sets the geometry of a GeometryModel3D. This is a dependency property.
        /// </summary>
        public Geometry3D Geometry
        {
            get
            {

                return (Geometry3D)this.GetValue(GeometryProperty);
            }
            set
            {
                Geometry3D OldValue = (Geometry3D)this.GetValue(GeometryProperty);
                if (OldValue != null)
                {
                    OldValue.PropertyChanged -= GeometryPropertyValue_PropertyChanged;
                }
                this.SetValue(GeometryProperty, value);
                value.PropertyChanged += GeometryPropertyValue_PropertyChanged;
            }
        }

        /// <summary>
        /// Notify if the some property of the Geometry was changed
        /// </summary>
        /// <param name="sender">Object that send the event</param>
        /// <param name="e">event arguments</param>
        void GeometryPropertyValue_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            this.IsDirty = true;
            this.NotifyPropertyChanged("Geometry");
        }

        /// <summary>
        /// Gets or sets the Material of a GeometryModel3D This is a dependency property.
        /// </summary>
        public Material Material
        {
            get
            {

                return (Material)this.GetValue(MaterialProperty);
            }
            set
            {
                Material OldValue = (Material)this.GetValue(MaterialProperty);
                if (OldValue != null)
                {
                    OldValue.PropertyChanged -= MaterialPropertyValue_PropertyChanged;
                }
                this.SetValue(MaterialProperty, value);
                value.PropertyChanged += MaterialPropertyValue_PropertyChanged;
            }
        }

        /// <summary>
        /// Notify if the some property of the Material was changed
        /// </summary>
        /// <param name="sender">Object that send the event</param>
        /// <param name="e">event arguments</param>
        void MaterialPropertyValue_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            this.IsDirty = true;
            this.NotifyPropertyChanged("Material");
        }

        #endregion

        #region Constructors
        
        /// <summary>
        /// Creates a new instance of GeometryModel3D.
        /// </summary>
        public GeometryModel3D() : base()
        {
        }
       
        /// <summary>
        /// Creates a new instance of GeometryModel3D with the specified Geometry3D and Material.
        /// </summary>
        /// <param name="geometry"></param>
        /// <param name="material"></param>
        public GeometryModel3D(Geometry3D geometry, Material material) : this()
        {
            this.Geometry = geometry;
            this.Material = material;
        }
        #endregion

        #region Methods
        /// <summary>
        /// Raise the BackMaterial changed event
        /// </summary>
        /// <param name="d">DependencyObject owner of the property</param>
        /// <param name="e">DependencyPropertyChangedEventArgs with the necesary information</param>
        private static void OnBackMaterialPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((GeometryModel3D)d).NotifyPropertyChanged("BackMaterial");
            ((GeometryModel3D)d).IsDirty = true;
        }

        /// <summary>
        /// Raise the Geometry changed event
        /// </summary>
        /// <param name="d">DependencyObject owner of the property</param>
        /// <param name="e">DependencyPropertyChangedEventArgs with the necesary information</param>
        private static void OnGeometryPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((GeometryModel3D)d).NotifyPropertyChanged("Geometry");
            ((GeometryModel3D)d).IsDirty = true;
        }

        /// <summary>
        /// Raise the Material changed event
        /// </summary>
        /// <param name="d">DependencyObject owner of the property</param>
        /// <param name="e">DependencyPropertyChangedEventArgs with the necesary information</param>
        private static void OnMaterialPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((GeometryModel3D)d).NotifyPropertyChanged("Material");
            ((GeometryModel3D)d).IsDirty = true;
        }

        internal override void CreateRenderEntities(RenderEntityPool entityPool)
        {
            if (this.Geometry == null)
            {
                return;
            }
            entityPool.ReturnToPool(this._cachedRenderEntities);
            _cachedRenderEntities.Clear();
            this.Geometry.CreateRenderEntities(entityPool, this.Material, this.BackMaterial);
            
            this._cachedRenderEntities.AddRange(this.Geometry.RenderEntenties);
        }

       
        #endregion

        protected override Rect3D GetBounds()
        {
            if (this.Transform != null && this.Geometry != null)
            {
                return this.Transform.TransformBounds(this.Geometry.Bounds);
            }
            else
            {
                if (this.Geometry != null)
                {
                    return this.Geometry.Bounds;
                }
                else
                {
                    return Rect3D.Empty;
                }
            }
        }
    }
}
